//#define USE_DUNGEONBUDDY_DLL
using System;
using System.Collections.Generic;
using System.Linq;
using Bots.DungeonBuddy.Enums;
using CommonBehaviors.Actions;
using Styx;
using Styx.CommonBot;
using Styx.CommonBot.Frames;
using Styx.Pathing;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Styx.TreeSharp;
using Action = Styx.TreeSharp.Action;

#if USE_DUNGEONBUDDY_DLL
using Bots.DungeonBuddyDll;
using Bots.DungeonBuddyDll.Profiles;
using Bots.DungeonBuddyDll.Attributes;
using Bots.DungeonBuddyDll.Helpers;

namespace Bots.DungeonBuddyDll.Dungeon_Scripts.Wrath_of_the_Lich_King
#else
    using Bots.DungeonBuddy.Profiles;
    using Bots.DungeonBuddy.Attributes;
    using Bots.DungeonBuddy.Helpers;
    namespace Bots.DungeonBuddy.Dungeon_Scripts.Wrath_of_the_Lich_King
#endif
{
    public class HallsOfStone : Dungeon
    {
        #region Overrides of Dungeon

        public override uint DungeonId
        {
            get { return 208; }
        }

        public override WoWPoint Entrance
        {
            get { return new WoWPoint(8921.595, -965.0018, 1039.163); }
        }

        //  public override bool IsFlyingCorpseRun
        //     {
        //         get { return true; }
        //     }

        public override void OnEnter()
        {
            _escortedBranToEncounter = false;
        }

        public override bool IsComplete
        {
            get
            {
                bool isComplete = base.IsComplete;
                // make sure we don't get stuck in here because 
                if (isComplete && ScriptHelpers.EventInProcess)
                    ScriptHelpers.EventInProcess = false;
                return isComplete;
            }
        }

        public override void RemoveTargetsFilter(List<WoWObject> units)
        {
            units.RemoveAll(
                ret =>
                {
                    WoWUnit unit = ret as WoWUnit;
                    if (unit != null)
                    {
                        if (unit.Entry == SjonnirTheIronshaperId && unit.HasAura("Lightning Ring") && Me.IsMelee() && Me.IsDps())
                            return true;
                    }
                    return false;
                });
        }

        public override void IncludeTargetsFilter(List<WoWObject> incomingunits, HashSet<WoWObject> outgoingunits)
        {
            foreach (var obj in incomingunits)
            {
                var unit = obj as WoWUnit;
                if (unit != null)
                {
                    if (unit.CurrentTargetGuid != 0 && unit.CurrentTarget.Entry == BrannId) // targeting Brann
                        outgoingunits.Add(unit);
                }
            }
        }

        public override void WeighTargetsFilter(List<Targeting.TargetPriority> units)
        {
            foreach (var priority in units)
            {
                var unit = priority.Object as WoWUnit;
                if (unit != null)
                {
                    if (unit.CurrentTarget != null && unit.CurrentTarget.Entry == BrannId)
                        priority.Score += 500;
                }
            }
        }

        #endregion

        private const uint BrannId = 28070;
        private const uint SjonnirTheIronshaperId = 27978;
        private bool _escortedBranToEncounter;

        private LocalPlayer Me
        {
            get { return StyxWoW.Me; }
        }

        [EncounterHandler(55835, "Kaldir Ironbane", Mode = CallBehaviorMode.Proximity, BossRange = 35)]
        public Composite QuestPickupHandler()
        {
            WoWUnit unit = null;
            return new PrioritySelector(
                ctx => unit = ctx as WoWUnit,
                new Decorator(
                    ctx => !Me.Combat && !ScriptHelpers.WillPullAggroAtLocation(unit.Location) && unit.QuestGiverStatus == QuestGiverStatus.Available,
                    ScriptHelpers.CreatePickupQuest(() => unit)),
                new Decorator(
                    ctx => !Me.Combat && !ScriptHelpers.WillPullAggroAtLocation(unit.Location) && unit.QuestGiverStatus == QuestGiverStatus.TurnIn,
                    ScriptHelpers.CreateTurninQuest(() => unit)));
        }

        [EncounterHandler(27977, "Krystallus")]
        public Composite KrystallusEncounter()
        {
            WoWUnit boss = null;
            // run from party members that have Petrifying Grip
            AddAvoidObject(ctx => StyxWoW.Me.HasAura("Petrifying Grip"), 15, u => u != StyxWoW.Me && u is WoWPlayer && ((WoWPlayer)u).HasAura("Petrifying Grip"));
            return new PrioritySelector(ctx => boss = ctx as WoWUnit);
        }

        [EncounterHandler(27975, "Maiden of Grief")]
        public Composite MaidenOfGriefEncounter()
        {
            const uint stormOfGriefId = 50752;
            AddAvoidObject(ctx => true, 9, stormOfGriefId);

            return new PrioritySelector();
        }

        [EncounterHandler(28234, "Tribunal of Ages", Mode = CallBehaviorMode.CurrentBoss)]
        public Composite TribunalOfAgesEncounter()
        {
            WoWUnit brann = null;
            const uint searingGazeId = 28265;
            const uint darkMatterTargetId = 28237;
            const uint tribunalOfAgesId = 28234;

            WoWGameObject chest = null, floor = null;
            var brannOriginalLoc = new WoWPoint(1077.41, 474.1604, 207.7255);
            var brannEncounterEntranceLoc = new WoWPoint(939.6468, 375.4893, 207.4221);
            var brannEncounterFinishedLoc = new WoWPoint(917.253, 351.925, 203.7064);

            AddAvoidObject(ctx => (StyxWoW.Me.IsLeader() && !StyxWoW.Me.IsActuallyInCombat) || StyxWoW.Me.IsFollower(), 6, searingGazeId);
            AddAvoidObject(ctx => (StyxWoW.Me.IsLeader() && !StyxWoW.Me.IsActuallyInCombat) || StyxWoW.Me.IsFollower(), 8, darkMatterTargetId);

            return new PrioritySelector(
                ctx =>
                {
                    floor = ObjectManager.GetObjectsOfType<WoWGameObject>().FirstOrDefault(o => o.Entry == 191527);
                    chest = ObjectManager.GetObjectsOfType<WoWGameObject>().FirstOrDefault(o => o.Entry == 190586 && o.CanUse());
                    brann = ObjectManager.GetObjectsOfType<WoWUnit>().FirstOrDefault(u => u.Entry == BrannId);
                    if (!_escortedBranToEncounter && brann != null)
                        _escortedBranToEncounter = brann.Location.DistanceSqr(brannEncounterEntranceLoc) < 5 * 5;
                    return ctx;
                },
                new Decorator(
                    ctx => !_escortedBranToEncounter,
                    new PrioritySelector(
                        new Decorator(
                            ctx => brann == null,
                            new PrioritySelector(
                                new Decorator(
                                    ctx => Targeting.Instance.FirstUnit == null && StyxWoW.Me.Location.DistanceSqr(brannOriginalLoc) > 50 * 50,
                                    new Action(ctx => ScriptHelpers.MoveTankTo(brannOriginalLoc))),
                                new Decorator(ctx => StyxWoW.Me.Location.DistanceSqr(brannOriginalLoc) <= 50 * 50, new Action(ctx => _escortedBranToEncounter = true)))),
                        new Decorator(ctx => brann != null, ScriptHelpers.CreateTankTalkToThenEscortNpc(28070, brannOriginalLoc, brannEncounterEntranceLoc)))),
                new Decorator(
                    ctx => _escortedBranToEncounter && chest == null,
                    new PrioritySelector(
                // talk to Brann to start the event.
                        new Decorator(
                            ctx => brann != null && brann.Location.DistanceSqr(brannEncounterEntranceLoc) < 3 * 3 && brann.CanGossip && StyxWoW.Me.IsLeader(),
                            ScriptHelpers.CreateTalkToNpc(() => brann)),
                // talk to Brann to make him stfu
                        new Decorator(
                            ctx => brann != null && brann.Location.DistanceSqr(brannEncounterFinishedLoc) < 3 * 3 && brann.CanGossip && StyxWoW.Me.IsLeader(),
                            ScriptHelpers.CreateTalkToNpc(() => brann)),
                // move to encounter area
                        new Decorator(
                            ctx => brann == null && StyxWoW.Me.Location.DistanceSqr(brannEncounterEntranceLoc) > 50 * 50 && StyxWoW.Me.IsTank(),
                            new Action(ctx => ScriptHelpers.MoveTankTo(brannEncounterEntranceLoc))),
                        new Decorator(
                            ctx =>
                            brann == null && StyxWoW.Me.Location.DistanceSqr(brannEncounterEntranceLoc) <= 15 * 15 && BossManager.CurrentBoss != null &&
                            BossManager.CurrentBoss.Entry == tribunalOfAgesId,
                            new Action(ctx => BossManager.CurrentBoss.MarkAsDead())),
                        new Decorator(ctx => StyxWoW.Me.IsLeader() && Targeting.Instance.FirstUnit == null && brann != null, new ActionAlwaysSucceed()) // don't go anywhere.
                        )));
        }

        [ObjectHandler(190586, "Chest")]
        public Composite ChestBehavior()
        {
            WoWGameObject chest = null;
            return new PrioritySelector(
                ctx => chest = ctx as WoWGameObject,
                new Decorator(
                    ctx => !StyxWoW.Me.Combat && chest != null && !chest.InUse && chest.CanUse() && !Blacklist.Contains(chest, BlacklistFlags.Loot),
                    new PrioritySelector(
                        new Decorator(ctx => !chest.WithinInteractRange, new Action(ctx => Navigator.MoveTo(chest.Location))),
                        new Sequence(
                                new DecoratorContinue(ctx => StyxWoW.Me.IsMoving, new Action(ctx => WoWMovement.MoveStop())),
                                new WaitContinue(2, ctx => !StyxWoW.Me.IsMoving, new ActionAlwaysSucceed()),
                                new Action(ctx => chest.Interact()),
                                new WaitContinue(3, ctx => false, new ActionAlwaysSucceed()),
                                new Action(ctx => LootFrame.Instance.LootAll()),
                                new Action(ctx => Blacklist.Add(chest, BlacklistFlags.Loot, TimeSpan.FromMinutes(10)))))));
        }

        [EncounterHandler(27978, "Sjonnir The Ironshaper", Mode = CallBehaviorMode.CurrentBoss)]
        public Composite SjonnirTheIronshaperEncounter()
        {
            WoWUnit boss = null;
            WoWUnit brann = null;
            var brannStartingLoc = new WoWPoint(1199.685, 667.155, 196.2405);
            AddAvoidObject(ctx => true, 10, o => o.Entry == SjonnirTheIronshaperId && o.ToUnit().HasAura("Lightning Ring"));
            AddAvoidObject(ctx => true, 6, u => u is WoWPlayer && !u.IsMe && (u.ToUnit().HasAura("Static Charge") || Me.HasAura("Static Charge")));

            return new PrioritySelector(
                ctx =>
                {
                    brann = ObjectManager.GetObjectsOfType<WoWUnit>().FirstOrDefault(u => u.Entry == BrannId);
                    return boss = ctx as WoWUnit;
                },
                new Decorator(
                    ctx => Targeting.Instance.FirstUnit == null && brann != null && brann.Location.DistanceSqr(brannStartingLoc) < 2 * 2, ScriptHelpers.CreateTalkToNpc(28070)),
                new Decorator(
                    ctx => boss != null, new PrioritySelector(ScriptHelpers.CreateDispellEnemy("Lightning Shield", ScriptHelpers.EnemyDispellType.Magic, () => boss))));
        }
    }
}